﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using GameEngine.animations;
using System.Xml;
namespace GameEngine.Scenes
{
    public class Actor : ICloneable
    {
        #region Attributes
        public Vector2 position;
        public float rotation;
        public float scale = 1;
        public Color color = Color.White;
        public OriginType originType; //relative
        public Vector2 drawingOffset; //absolute
        public List<DetailAnimation> detailAnimations { get; set; }
        public int currentAnimation { get; set; }
        #endregion  
        
        public Actor(XmlElement element) { 
        
        
        }

        public Actor(Vector2 position, float rotation, float scale, OriginType originType) 
        {
            this.position = position;
            this.rotation = rotation;
            this.scale = scale;
            this.originType = originType;
            this.drawingOffset = new Vector2();
            detailAnimations = new List<DetailAnimation>();
        }
        public Actor() :
            this(new Vector2(), 0, 1, OriginType.CENTER)
        { }
        #region Functionality
        public DetailAnimation getCurrentDetailAnimation() 
        {
            return detailAnimations[currentAnimation];
        }
        public Animation getCurrentAnimation() 
        {
            return detailAnimations[currentAnimation].animation;
        }

        public virtual void update(int dTime)
        {
            if (detailAnimations.Count > 0)
            {
                DetailAnimation curDetAnim = detailAnimations[currentAnimation];
                if (curDetAnim != null)
                    curDetAnim.update(dTime);
            }
        }

        public virtual void draw(SpriteBatch sb)
        {
            if (detailAnimations.Count > 0)
            {
                DetailAnimation curDetAnim = detailAnimations[currentAnimation];
                if (curDetAnim != null)
                {
                    Animation curAnim = curDetAnim.animation;
                    if (curAnim != null)
                    {
                        Vector2 origin = new Vector2()+ drawingOffset;
                        switch (originType)
                        {
                            case OriginType.CENTER:
                                origin += curAnim.getFrameSize() / 2;
                                break;
                            case OriginType.LEFT_UP:
                                origin += Vector2.Zero;
                                break;
                            case OriginType.CENTER_DOWN:
                                origin += curAnim.getFrameSize();
                                origin.X /= 2;
                                break;
                            default:
                                origin += curAnim.getFrameSize() / 2;
                                break;
                        }
                        SpriteEffects mirrored = (curDetAnim.mirroredHor? SpriteEffects.FlipHorizontally: SpriteEffects.None) |
                            (curDetAnim.mirroredVer ? SpriteEffects.FlipVertically : SpriteEffects.None) ;
                        if (curDetAnim.postProcessEffect == null) //Draw normally
                        {
                            drawNormally(sb, curDetAnim, origin, mirrored);
                        }
                        else //render to a different target & then render to the screen to add an effect
                        {
                            drawWithEffect(sb, curDetAnim, origin, mirrored, curDetAnim.postProcessEffect);
                        }
                    }
                }
            }
        }
        private void drawNormally(SpriteBatch sb, DetailAnimation detAnim, Vector2 origin, SpriteEffects mirrored)
        {
            if (detAnim is DetailAnimationComposed) //if has additional animations
            {
                sb.Draw(detAnim.animation.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
                foreach (Animation anim in ((DetailAnimationComposed)detAnim).childAnimations)
                {
                    sb.Draw(anim.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
                }
            }
            else
            {
                sb.Draw(detAnim.animation.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
            }
        }
        private void drawWithEffect(SpriteBatch sb, DetailAnimation detAnim, Vector2 origin, SpriteEffects mirrored, PostProcessEffect ppe) 
        {
            sb.End(); //stop drawing to the screen
            sb.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None); //start drawing
            ppe.effect.Begin();
            foreach (EffectPass pass in ppe.technique.Passes)
            {
                pass.Begin();
                if (detAnim is DetailAnimationComposed) //if has additional animations
                {
                    sb.Draw(detAnim.animation.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
                    foreach (Animation anim in ((DetailAnimationComposed)detAnim).childAnimations)
                    {
                        sb.Draw(anim.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
                    }
                }
                else
                {
                    sb.Draw(detAnim.animation.texture, position, detAnim.getRect(), color, rotation, origin, scale, mirrored, 1);
                }
                pass.End();
            }
            ppe.effect.End();
            sb.End(); sb.Begin();//finish this draw & start a new one
        }
        #endregion

        #region ICloneable Members
        public virtual object Clone()
        {
            Type type = this.GetType();
            Actor newActor = (Actor)Activator.CreateInstance(type);
            newActor.position = position;
            newActor.rotation = rotation;
            newActor.scale = scale;
            newActor.originType = originType;
            newActor.currentAnimation = this.currentAnimation;
            newActor.drawingOffset = this.drawingOffset;
            if (this.detailAnimations != null && this.detailAnimations.Count > 0) {
                foreach (DetailAnimation dA in this.detailAnimations) {
                    newActor.detailAnimations.Add((DetailAnimation)dA.Clone());
                }
            }
            return newActor;
        }
        #endregion
    }
}
